export default class Snake{
    //表示蛇头的元素
    head:HTMLElement;
    //蛇的身体（包括蛇头）
    //HTMLCollection:HTML 元素的集合。
    //getElementsByTagName() 方法返回的就是一个 HTMLCollection 对象。
    bodies:HTMLCollection;
    //获取蛇的容器
    element:HTMLElement;
    constructor(){
        this.element = document.getElementById('snake')!;
        //获取snake里的第一个div，同时标记获取的元素类型HTMLElement
        this.head = document.querySelector('#snake > div') as HTMLElement;
        //获取了snake下的所有div
        this.bodies = this.element.getElementsByTagName('div')
    }

    //获取蛇的坐标（蛇头的坐标）
    //X轴坐标
    get X(){
        return this.head.offsetLeft;
    }
    //Y轴坐标
    get Y(){
        return this.head.offsetTop
    }

    // 设置蛇头的坐标
    set X(value){
        //如果新值和旧值相同，则直接返回不进行修改
        if(this.X === value){
            return;
        }

        //X值的合法范围在[0,290]之间
        if(value < 0 || value > 290){
            //进入判断，证明蛇撞墙了
            throw new Error('蛇撞墙了!');
        }
        //修改x时，是在修改水平坐标，蛇在左右移动，蛇在向左移动时，不能向右掉头，反之亦然
        if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value){
            console.log("水平方向发生了掉头");
            //如果发生调用，让蛇反方向继续移动
            if(value > this.X){
                // 如果新值value大于旧值X，则说明蛇在向右走，此时发生掉头，应该使蛇继续向左走
                value = this.X - 10;
            }else{
                 // 向左走
                 value = this.X + 10;
            }
            
        }
        //移动身体
        this.moveBody();

        this.head.style.left = value + 'px';
        // 检查有没有撞到自己
        this.checkHeadBody();

    }
    set Y(value){
         // 如果新值和旧值相同，则直接返回不再修改
         if(this.Y === value){
            return;
        }
         // Y的值的合法范围0-290之间
         if(value < 0 || value > 290){
            // 进入判断说明蛇撞墙了，抛出一个异常
            throw new Error('蛇撞墙了！');
        }
        //修改y时，是在修改垂直坐标，蛇在上下移动，蛇在向上移动时，不能向下掉头，反之亦然
        if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value){
        if(value > this.Y){
            value = this.Y - 10;
        }else{
            value = this.Y + 10;
        }
    }
        //移动身体
        this.moveBody();
        this.head.style.top = value + 'px';
        //检查有没有撞到自己
        this.checkHeadBody();
    }
    

    //insertAdjacentHTML() 方法将一个给定的元素节点插入到相对于被调用的元素的给定的一个位置
    // 'beforebegin'：元素自身的前面。
    // 'afterbegin'：插入元素内部的第一个子节点之前。
    // 'beforeend'：插入元素内部的最后一个子节点之后。
    // 'afterend'：元素自身的后面。
    addBody(){
        //向element中添加div
        this.element.insertAdjacentHTML("beforeend", "<div></div>");
    }

    //添加一个蛇身体移动的方法
    moveBody(){
        /*
        *   将后边的身体设置为前边身体的位置
        *       举例子：
        *           第4节 = 第3节的位置
        *           第3节 = 第2节的位置
        *           第2节 = 蛇头的位置
        * */
       //遍历获取所有的身体
       for(let i = this.bodies.length-1;i>0;i--){
            //获取前面身体的位置
       let X = (this.bodies[i-1] as HTMLElement).offsetLeft;
       let Y = (this.bodies[i-1] as HTMLElement).offsetTop;

       //将值设置到当前的身体上
       (this.bodies[i] as HTMLElement).style.left = X + 'px';
       (this.bodies[i] as HTMLElement).style.top = Y + 'px';

       }
      
    }

    //检查蛇头是否撞到身体的方法
    checkHeadBody(){
        //获取所有的身体，检查其是否和蛇头的坐标发生重叠
        for(let i =1 ;i<this.bodies.length;i++){
            let bd = this.bodies[i] as HTMLElement;
            if(this.X === bd.offsetLeft && this.Y === bd.offsetTop){
                //进入判断说明蛇头撞到了身体，游戏结束
                throw new Error('撞到自己了！')
            }
           
        }
    }

}
